/*
 * InvertedListRecord.h
 *
 *  Created on: Nov 29, 2012
 *      Author: m
 */

#ifndef INVERTEDLISTRECORD_H_
#define INVERTEDLISTRECORD_H_

#include <vector>
#include "../common_components/physical_layer_commons.h"
#include "../serializers/InvertedListSerializer.h"
//#include "../compressors/CompressorMock.h"
#include "../compressors/GammaEliasFede/GammaEliasFede.h"
#include "InvertedList.h"

#define ILR_CONTENT_MAXSIZE 128

namespace physical
{

/**
 * Registro de Listas Invertidas
 *
 * explicar, basicamente contiene una lista invertida "comprimida"
 *  pero esa compresión es transparente
 */
class InvertedListRecord
{
public:

    /**
     * Constructor por defecto (con id inválida por defecto)
     */
    InvertedListRecord( term_id_t termID = 0 ) :
            m_termID( termID ),
            m_content(),
            m_contentSerializer( new InvertedListSerializer ),
            m_contentCompressor( new GammaEliasCoder )
    {
    }

    /**
     * Constructor por copia
     */
    InvertedListRecord( const InvertedListRecord &other ) :
        m_contentSerializer( new InvertedListSerializer ),
        m_contentCompressor( new GammaEliasCoder )
    {
        *this = other;
    }

    /**
     * Constructor por Lista Invertida
     *
     * Explicar: Básicamente recibe una lista invertida, y
     * para guardarla, la comprime. Pero esto es transparente
     */
    InvertedListRecord( term_id_t termID, const InvertedList &content ) :
            m_termID( termID ),
            m_content(),
            m_contentSerializer( new InvertedListSerializer ),
            m_contentCompressor( new GammaEliasCoder )
    {
        this->setContent( content );
    }

    /**
     * Constructor por Contenido ( Lista Invertida comprimida )
     *
     * @param termID ID del término asociado a la lista invertida
     * @param content La lista invertida YA comprimida
     * @param contentSize El tamaño del contenido
     */
    InvertedListRecord( term_id_t termID, const byte* content, size_t contentSize ) :
            m_termID( termID ),
            m_content( content, content + contentSize ),
            m_contentSerializer( new InvertedListSerializer ),
            m_contentCompressor( new GammaEliasCoder )
    {
    }

    /**
     * Destructor
     */
    virtual ~InvertedListRecord()
    {
    }

    /**
     * Devuelve el termID de la lista invertida contenida en el registro
     *
     * @return El termID de la lista invertida contenida en el registro
     */
    term_id_t getID()
    {
        return m_termID;
    }

    /**
     * Carga una nueva lista invertida en el registro
     *
     * @param newContent
     */
    void setInvertedList( const InvertedList &newContent )
    {
        this->setContent( newContent );
    }

    /**
     * Devuelve la lista invertida contenida en el registro
     *
     * @return
     */
    InvertedList getInvertedList() const
    {
        InvertedList result;

        this->getContent( result );

        return result;
    }

    /**
     * Operador de asignación
     *
     * @param other
     * @return
     */
    InvertedListRecord& operator =( const InvertedListRecord& other )
    {
         m_termID  = other.m_termID;
         m_content = other.m_content;

        return *this;
    }

    /**
     * Operador de comparación por igualdad
     *
     * @param other el elemento con el que se compara
     * @return true si es igual, false en caso contrario
     */
    bool operator ==( const InvertedListRecord& other ) const
    {
         return m_termID  == other.m_termID &&
                m_content == other.m_content;
    }

    /**
     * Operador de comparación por desigualdad
     *
     * @param other el elemento con el que se compara
     * @return true si no es igual, false en caso contrario
     */
    bool operator !=( const InvertedListRecord& other ) const
    {
        return !( *this == other );
    }

protected:
    term_id_t m_termID;
    std::vector<byte> m_content;
    std::unique_ptr< Serializer< InvertedList > > m_contentSerializer;
    std::unique_ptr< Compressor > m_contentCompressor;

    friend class InvertedListRecordSerializer;

    /**
     * Guarda una InvertedList en el registro
     *
     * Serializa y comprime d forma transparente
     *
     * @param newContent InvertedList a setear como content
     */
    void setContent( const InvertedList &newContent )
    {
        byte serializedData[ILR_CONTENT_MAXSIZE];
        byte compressedData[ILR_CONTENT_MAXSIZE];
        size_t serializedDataSize;
        size_t compressedDataSize;

        /*
         * Serializar y comprimir la lista invertida
         */
        serializedDataSize = m_contentSerializer->serialize( newContent,
                serializedData );

        compressedDataSize = m_contentCompressor->compress( serializedData,
                compressedData, serializedDataSize );

        /*
         * Guardar el resultado
         */
        m_content.assign( compressedData, compressedData + compressedDataSize );
    }

    /**
     * Devuelve la InvertedList contenida en el registro
     *
     * Descomprime y deserializa de forma transparente
     *
     * @param result La InvertedList en la que se devuelve el contenido
     */
    void getContent( InvertedList &result ) const
    {
        byte uncompressedData[ILR_CONTENT_MAXSIZE];

        /*
         * Descomprimir y de-serializar la lista invertida
         */
        m_contentCompressor->uncompress( &m_content.front(),
                uncompressedData, m_content.size() );

        m_contentSerializer->deserialize( uncompressedData, result );
    }
};

} /* namespace physical */
#endif /* INVERTEDLISTRECORD_H_ */
